/*******************************************************************************
*
*
*******************************************************************************/
#include "bsp.h"
#include "taskmanger.h"


#define APP_TIM TIM6
#define APP_TIM_IRQn TIM6_IRQn
#define app_timer_isr TIM6_IRQHandler

#define APP_TIM_PERIOD 1000

/******************************************************************************
*	                            function
*******************************************************************************/
uint32_t app_tick_init(uint32_t TickPriority);
void app_tick_suspend(void);
void app_tick_resume(void);
uint32_t app_tick_get(void);
uint32_t app_tick_us_get(void);
void app_tick_isr(void);

/******************************************************************************
*	                            var
*******************************************************************************/
static volatile uint32_t hal_tick_cnt = 0;
static vtask_vector_type task_vect;
static void (*task_list[8])(void);

/*******************************************************************************
* @brief  app_tick_init
* \param[in] none
* \retval: none
*******************************************************************************/
uint32_t app_tick_init(uint32_t TickPriority)
{
	RCC_ClocksType clocks;
	
	intx_alloc();

	// 使能定时器时钟
	intx_disable();
	RCC_APB1_Peripheral_Clock_Enable(RCC_APB1_PERIPH_TIM6);
	vtask_list_init(&task_vect, task_list, sizeof(task_list)/4, 0);
	intx_enable();

	// 获取时钟值
	RCC_Clocks_Frequencies_Value_Get(&clocks);

	// 配置
	APP_TIM->CTRL1 = 0;
	APP_TIM->CTRL2 = 0;

	APP_TIM->DINTEN = 0;
	APP_TIM->STS = 0;

	/*1ms interrupt*/
	APP_TIM->PSC = (clocks.Pclk1Freq / 1000000) * 2 - 1;
	APP_TIM->AR = APP_TIM_PERIOD - 1;

	// nvic
	nvic_irq_set(APP_TIM_IRQn, 0x03, 1);

	APP_TIM->CTRL1 = TIM_CTRL1_UPRS | TIM_CTRL1_CNTEN;

	APP_TIM->DINTEN = TIM_DINTEN_UIEN;

	return 0;
}

/*******************************************************************************
* @brief  app_tick_suspend
* \param[in] none
* \retval: none
*******************************************************************************/
void app_tick_suspend(void)
{
	APP_TIM->DINTEN = 0;
}

/*******************************************************************************
* @brief  app_tick_resume
* \param[in] none
* \retval: none
*******************************************************************************/
void app_tick_resume(void)
{
	APP_TIM->DINTEN = TIM_DINTEN_UIEN;
}

/*******************************************************************************
* @brief  app_tick_get
* \param[in] none
* \retval: none
*******************************************************************************/
uint32_t app_tick_get(void)
{
	return hal_tick_cnt;
}

/*******************************************************************************
* @brief  app_tick_us_get, 未处理溢出问题，仅可用于调试目的
* \param[in] none
* \retval: none
*******************************************************************************/
uint32_t app_tick_us_get(void)
{
	uint32_t time_us, tick_now;

	do
	{
		tick_now = hal_tick_cnt;
		
		time_us = tick_now * APP_TIM_PERIOD;

		time_us += APP_TIM->CNT & 0x0000FFFF;	

	} while(tick_now != hal_tick_cnt);
	
	return time_us;
}

/*******************************************************************************
* @brief  app_tick_isr
* \param[in] none
* \retval: none
*******************************************************************************/
void app_timer_isr(void)
{
	APP_TIM->STS = 0;

	hal_tick_cnt++;
	
	os_isr_entry();
	
	vtask_list_run_once_nohook(&task_vect);
	
	os_isr_exit();
}

/*******************************************************************************
* @brief  app timer task add
* \param[in] none
* \retval: none
*******************************************************************************/
void app_timer_task_add(void (*task)(void))
{
	intx_alloc();

	intx_disable();
	
	vtask_list_add(&task_vect, task);
	
	intx_enable();
}

/*******************************************************************************
* @brief  app timer task del
* \param[in] none
* \retval: none
*******************************************************************************/
void app_timer_task_del(void (*task)(void))
{
	intx_alloc();

	intx_disable();
	
	vtask_list_del(&task_vect, task);
	
	intx_enable();
}
